#include "mpu6050.h"
#include "filter.h"

#include "math.h"

uint8_t MPU_Init(void)
{
	uint8_t res;

	MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00);	//唤醒MPU6050

	MPU_Set_Rate(125);						//设置采样率125Hz
	MPU_Set_Gyro_Fsr(3);					//陀螺仪传感器,±2000dps
	MPU_Set_Accel_Fsr(0);					//加速度传感器,±2g

	res=MPU_Read_Byte(MPU_DEVICE_ID_REG);		//获取ID
	printf("\r\nMPU6050:0x%2x\r\n",res);
	if(res==MPU_ADDR)//器件ID正确
	{
//			MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01);	//设置CLKSEL,PLL X轴为参考
//			MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00);	//加速度与陀螺仪都工作
//			MPU_Set_Rate(200);						//设置采样率200Hz
	}else return 1;
	return 0;
}
 
//设置MPU6050陀螺仪传感器满量程范围
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0,设置成功
//    其他,设置失败
uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr)
{
	return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3);//设置陀螺仪满量程范围
}
//设置MPU6050加速度传感器满量程范围
//fsr:0,±2g;1,±4g;2,±8g;3,±16g
//返回值:0,设置成功
//    其他,设置失败
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr)
{
	return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3);//设置加速度传感器满量程范围
}
//设置MPU6050的数字低通滤波器
//lpf:数字低通滤波频率(Hz)
//返回值:0,设置成功
//    其他,设置失败
uint8_t MPU_Set_LPF(uint16_t lpf)
{
	uint8_t data=0;
	if(lpf>=188)data=1;
	else if(lpf>=98)data=2;
	else if(lpf>=42)data=3;
	else if(lpf>=20)data=4;
	else if(lpf>=10)data=5;
	else data=6; 
	return MPU_Write_Byte(MPU_CFG_REG,data);//设置数字低通滤波器
}
//设置MPU6050的采样率(假定Fs=1KHz)
//rate:4~1000(Hz)
//返回值:0,设置成功
//    其他,设置失败
uint8_t MPU_Set_Rate(uint16_t rate)
{
	uint8_t data;
	if(rate>1000)rate=1000;
	if(rate<4)rate=4;
	data=1000/rate-1;
	data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data);	//设置数字低通滤波器
// 	return MPU_Set_LPF(rate/2);	//自动设置LPF为采样率的一半
	return MPU_Set_LPF(5);
}

//得到温度值
//返回值:温度值(扩大了100倍)
short MPU_Get_Temperature(void)
{
    uint8_t buf[2]; 
    short raw;
	float temp;
	MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf); 
    raw=((uint16_t)buf[0]<<8)|buf[1];  
    temp=36.53+((double)raw)/340;  
    return temp*100;;
}
//得到陀螺仪值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
uint8_t MPU_Get_Gyroscope(short *gx,short *gy,short *gz)
{
    uint8_t buf[6],res;  
	res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
	if(res==0)
	{
		*gx=((uint16_t)buf[0]<<8)|buf[1];  
		*gy=((uint16_t)buf[2]<<8)|buf[3];  
		*gz=((uint16_t)buf[4]<<8)|buf[5];
	} 	
    return res;;
}
//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
uint8_t MPU_Get_Accelerometer(short *ax,short *ay,short *az)
{
    uint8_t buf[6],res;  
	res=MPU_Read_Len(MPU_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);
	if(res==0)
	{
		*ax=((uint16_t)buf[0]<<8)|buf[1];  
		*ay=((uint16_t)buf[2]<<8)|buf[3];  
		*az=((uint16_t)buf[4]<<8)|buf[5];
	} 	
    return res;;
}
//IIC连续写
//addr:器件地址
//reg:寄存器地址
//len:写入长度
//buf:数据区
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Write_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf)
{
	uint8_t i; 
  i2c_Start(); 
	i2c_SendByte((addr<<1)|0);//发送器件地址+写命令
	if(i2c_WaitAck())	//等待应答
	{
		i2c_Stop();		 
		return 1;		
	}
    i2c_SendByte(reg);	//写寄存器地址
    i2c_WaitAck();		//等待应答
	for(i=0;i<len;i++)
	{
		i2c_SendByte(buf[i]);	//发送数据
		if(i2c_WaitAck())		//等待ACK
		{
			i2c_Stop();	 
			return 1;		 
		}		
	}    
    i2c_Stop();	 
	return 0;	
} 
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Read_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf)
{ 
 	i2c_Start(); 
	i2c_SendByte((addr<<1)|0);//发送器件地址+写命令
	if(i2c_WaitAck())	//等待应答
	{
		i2c_Stop();		 
		return 1;		
	}
    i2c_SendByte(reg);	//写寄存器地址
    i2c_WaitAck();		//等待应答
    i2c_Start();
	i2c_SendByte((addr<<1)|1);//发送器件地址+读命令
    i2c_WaitAck();		//等待应答
	while(len)
	{
		if(len==1)*buf=i2c_ReadByte(0);//读数据,发送nACK
		else *buf=i2c_ReadByte(1);		//读数据,发送ACK
		len--;
		buf++; 
	}    
    i2c_Stop();	//产生一个停止条件
	return 0;	
}
//IIC写一个字节
//reg:寄存器地址
//data:数据
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Write_Byte(uint8_t reg,uint8_t data) 				 
{ 
    i2c_Start(); 
	i2c_SendByte((MPU_ADDR<<1)|0);//发送器件地址+写命令
	if(i2c_WaitAck())	//等待应答
	{
		i2c_Stop();		 
		return 1;		
	}
    i2c_SendByte(reg);	//写寄存器地址
    i2c_WaitAck();		//等待应答
	i2c_SendByte(data);//发送数据
	if(i2c_WaitAck())	//等待ACK
	{
		i2c_Stop();	 
		return 1;		 
	}		 
    i2c_Stop();	 
	return 0;
}
//IIC读一个字节
//reg:寄存器地址
//返回值:读到的数据
uint8_t MPU_Read_Byte(uint8_t reg)
{
	uint8_t res;
    i2c_Start(); 
	i2c_SendByte((MPU_ADDR<<1)|0);//发送器件地址+写命令
	i2c_WaitAck();		//等待应答
    i2c_SendByte(reg);	//写寄存器地址
    i2c_WaitAck();		//等待应答
    i2c_Start();
	i2c_SendByte((MPU_ADDR<<1)|1);//发送器件地址+读命令
    i2c_WaitAck();		//等待应答
	res=i2c_ReadByte(0);//读取数据,发送nACK
    i2c_Stop();			//产生一个停止条件
	return res;		
}

///**************************************************************************
//函数功能：获取角度 0-359
//入口参数：无
//返回  值：无
//**************************************************************************/
//void getAngle(float *yaw,float *yaw_acc_error)
//{
//	Read_DMP();                   //===读取Yaw(-180 - 179)
//	
//	if(Yaw < 0)
//		Yaw = Yaw + 360;
//	*yaw = Yaw;                   //===转换yaw(   0 - 359)
//	
//	*yaw = *yaw - *yaw_acc_error; //===减去yaw随时间的向上漂移
//	
//	if(*yaw < 0)
//		*yaw = *yaw+360;
//}


/*************************************************************
函数功能：获取x方向的角度
输入参数：way:1：四元素算法，2、卡尔曼滤波，3、互补滤波
测量xyz哪一个方向的角度0：x，1：y，2：z，只针对卡尔曼滤波和互补滤波
返回参加：g_Attitude：通过结构体变量返回x、y、z的偏角
注；滤波后的参数，直接传递给全局变量。
**************************************************************/
//#define DT 0.005    //微分时间一般取0.005
//
//void Get_Angle(void)
//{
//	short accx,accy,accz,gyrox,gyroy,gyroz;
//
//	MPU_Get_Accelerometer(&accx,&accy,&accz);	//得到加速度传感器数据
//	MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);	//得到陀螺仪数据
//
//
//	g_MPUManager.accX = accx;
//	g_MPUManager.accY = accy;
//	g_MPUManager.accZ = accz;
//	g_MPUManager.gyroX = gyrox;
//	g_MPUManager.gyroY = gyroy;
//	g_MPUManager.gyroZ = gyroz;
//
//  ATT_Update(&g_MPUManager,&g_Attitude,DT);           //四元素算法
//
//}


#define gyro_offset 0.0

void Get_KalmanAngle(float *angle_,float *angle_dot_,uint8_t PRY)
{
	float Angle_temp,gyro_temp;
	short accx,accy,accz,gyrox,gyroy,gyroz;
//	float real_accx,real_gyro;
	MPU_Get_Accelerometer(&accx,&accy,&accz);	//得到加速度传感器数据
	MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);	//得到陀螺仪数据
	
	
	switch(PRY)
	{
		case 'P'://Pitch
//					Angle_temp = ((float)atan2(1.0*accx,accz)) * (57.2957795);
		
					Angle_temp = atan2(1.0*accx, sqrtl( powl(accy,2) + powl(accz,2) ))* (57.2957795);
					gyro_temp = (float)(1.0 * gyroy / 16.4);
					Kalman_Filter(Angle_temp,gyro_temp,angle_,angle_dot_); 
			break;
		
		case 'R'://Roll
//					Angle_temp = ((float)atan2(1.0*accy,accz)) * (57.2957795);
					Angle_temp = atan2(1.0*accy, sqrtl( powf(accx,2) + powl(accz,2) ))* (57.2957795);
					gyro_temp = (float)(1.0 * gyrox / 16.4);
					Kalman_Filter(Angle_temp,gyro_temp,angle_,angle_dot_); 
			break;
		
		case 'Y'://Yaw
			
					Angle_temp = Angle_temp + ((1.0 * gyrox / 16.4)+gyro_offset) * 0.05;
		
			break;
	}
	
	
	
}
